import { IAceEditorProps } from 'react-ace';
import { MonacoEditorProps } from 'react-monaco-editor';

/** 计算函数类型 */
export type ICalculateType =
  | 'sum'
  | 'avg'
  | 'max'
  | 'min'
  | 'nvl'
  | 'distinct'
  | 'concat'
  | 'count'
  | 'count(distinct)'
  | 'count(distinct concat())'
  // 以下是操作运算符
  | 'and'
  | 'or'
  | '('
  | ')'
  | '+'
  | '-'
  | '*'
  | '/'
  | '>'
  | '<';

/** 计算函数 */
export const CalculateFuncs: LabelValue<ICalculateType>[] = [
  { label: 'sum', value: 'sum' },
  { label: 'avg', value: 'avg' },
  { label: 'max', value: 'max' },
  { label: 'min', value: 'min' },
  { label: 'nvl', value: 'nvl' },
  { label: 'distinct', value: 'distinct' },
  { label: 'concat', value: 'concat' },
  { label: 'count', value: 'count' },
  { label: 'count(distinct)', value: 'count(distinct)' },
  { label: 'count(distinct concat())', value: 'count(distinct concat())' },
  // ...SpecialCalculateFunc,
];

/** 计算操作符 */
export const CalculateOperators: LabelValue<ICalculateType>[] = [
  { label: 'and', value: 'and', style: { fontSize: 14, fontWeight: 'bold' } },
  { label: 'or', value: 'or', style: { fontSize: 14, fontWeight: 'bold' } },
  { label: '(', value: '(', style: { fontSize: 14, fontWeight: 'bold' } },
  { label: ')', value: ')', style: { fontSize: 14, fontWeight: 'bold' } },
  { label: '+', value: '+', style: { fontSize: 18, fontWeight: 'bold' } },
  { label: '-', value: '-', style: { fontSize: 18, fontWeight: 'bold' } },
  {
    label: '*',
    value: '*',
    style: { fontSize: 18, fontWeight: 'bold', paddingTop: 5 },
  },
  { label: '/', value: '/', style: { fontSize: 16, fontWeight: 'bold' } },
  { label: '>', value: '>', style: { fontSize: 18, fontWeight: 'bold' } },
  { label: '<', value: '<', style: { fontSize: 18, fontWeight: 'bold' } },
];

/** 编辑器操作事件类型 */
export type IEditorOperateType =
  | 'run'
  | 'task'
  | 'init'
  | 'insert'
  | 'undo'
  | 'redo'
  | 'reset'
  | 'save'
  | 'format'
  | 'screenFull'
  | 'theme'
  | 'mode'
  | 'setting';

export interface IEditorOperateEvent {
  type: IEditorOperateType;
  data?: string;
}

/** 编辑器js_beautify格式化属性默认值与设置项 */
export const jsBeautifyOptions = {
  eol: '\n', // all.行结束符
  end_with_newline: false, // all,确保在文件结束时换行
  indent_char: '\t', // all,缩进字符，默认" "，\t 跳格(移至下一列)
  indent_size: 2, // all,缩进尺寸，默认4
  indent_with_tabs: true, // all,使用tab缩进,将会覆盖“indent_size”和“indent_char”设置，默认false
  preserve_newlines: true, // all,保留空行，默认“true”（保留换行符）
  max_preserve_newlines: 2, // html、js,保留连续换行符个数，默认10（比如设为2，则会将2行以上的空行删除为只保留1行）
  wrap_line_length: 0, // html、js,在 n 个字符之后换行(设置为0忽略换行)

  html: {
    extra_liners: ['head', 'body', '/html'], // 配置标签列表，需要在这些标签前面额外加一空白行（换行符）
    indent_body_inner_html: false, // 缩进 < body> 中的元素，默认：true
    indent_handlebars: true, // 格式和缩进，默认为false
    indent_head_inner_html: false, // 缩进 < head> 中的元素，默认：true
    indent_inner_html: true, // 缩进< head>和< body>中的元素（head和body也会缩进），默认：false
    indent_scripts: 'normal', // 缩进< script> 标签里的代码，有三个值：“keep”(对齐< script>标签)、“separate”(对齐左边界)、“normal”(正常缩进)，默认：“normal”
    inline: [], // 各种标签的缩进[ "a", "abbr", "area", "audio", "b", "bdi", "bdo", "br", "button", "canvas", "cite", "code", "data", "datalist", "del", "dfn", "em", "embed", "i", "iframe", "img", "input", "ins", "kbd", "keygen", "label", "map", "mark", "math", "meter", "noscript", "object", "output", "progress", "q", "ruby", "s", "samp", "select", "small", "span", "strong", "sub", "sup", "svg", "template", "textarea", "time", "u", "var", "video", "wbr", "text", "acronym", "address", "big", "dt", "ins", "strike", "tt" ]
    wrap_attributes: 'auto', // 将属性换到新行，有5个值：“auto”(不换行)、“force”(第2个起换行)、 “force-aligned”(第2个起换行，与第1个属性对齐)、 “force-expand-multiline(所有属性都换行)，默认：“auto”
    wrap_attributes_indent_size: 4, // 属性换行缩进大小,默认：indent_size
    unformatted: [], // 数组中的标签不会重新格式化，默认：[]
    content_unformatted: [], // 数组中标签的内容不会重新格式化，默认：[“pre”,“textarea”]
    void_elements: [], // 定义自关闭标签,["area", "base", "br", "col", "embed", "hr", "img", "input", "keygen", "link", "menuitem", "meta", "param", "source", "track", "wbr", "!doctype", "?xml", "?php", "?=", "basefont", "isindex"]
  },
  js: {
    brace_style: 'collapse', // 括号风格，“collapse-preserve-inline”, “collapse”, “expand”, “end-expand”, or “none” ,默认“collapse”
    break_chained_methods: true, // 中断多行间的链式方法调用，默认true
    comma_first: false, // 将逗号放在新行的开头而不是结尾，默认为false
    e4x: true, // 不受影响地传递E4X xml文本,默认为false
    indent_level: 0, // 初始缩进级别
    jslint_happy: true, // 开启jslint-stricter的严格模式（强制开启“space_after_anon_function”选项）,默认false
    keep_array_indentation: true, // 保持数组缩进，默认false
    keep_function_indentation: true, // 保持函数缩进，默认false
    operator_position: 'before-newline', // 将操作符移动到新行之前或之后，或保持原样。“before-newline”， “after-newline”，或"preserve-newline",默认为"before-newline"
    space_after_anon_function: true, // 在匿名函数的括号前加空格,默认为false
    space_after_named_function: true, // 在具名函数之前加一个空格
    space_before_conditional: true, // 在条件语句之前保留一个空格，默认true
    space_in_empty_paren: true, // 在括号中留空格，默认为false
    space_in_paren: true, // 在函数参数之间增加空格，默认为false
    unescape_strings: true, // 解码用xNN表示法编码的可打印字符,默认为false
    unindent_chained_methods: true, // Unindent链接方法,默认为false
  },
  css: {
    newline_between_rules: false, //在css规则之间添加一个换行符，默认为false
    selector_separator_newline: true, //在多个选择器之间加一个换行符
    space_around_combinator: false, //确保选择器分隔符周围的空间 (>+~)
  },
};

export const EditorList = ['ace', 'monaco'] as const;
export const EditorLanguageList = [
  'java',
  'javascript',
  'json',
  'sql',
] as const;
export const EditorThemeList = ['light', 'dark', 'black'] as const;
export const EditorThemeMap = {
  // ace: { light: 'xcode', dark: 'monokai', black: 'mono_industrial' },
  ace: { light: 'xcode', dark: 'monokai', black: 'solarized_dark' },
  monaco: { light: 'vs', dark: 'vs-dark', black: 'hc-black' },
};
export const EditorFontSizeList = [12, 13, 14, 15, 16, 18, 20, 22, 24];
export const EditorReadOnlyOptions = [
  { label: '是', value: true },
  { label: '否', value: false },
];

export type IEditorType = (typeof EditorList)[number];
export type IEditorLanguage = (typeof EditorLanguageList)[number];
export type IEditorTheme = (typeof EditorThemeList)[number];
export type IEditorFontSize = (typeof EditorFontSizeList)[number];

/** ACE自定义提示类型 */
export interface IEditorCompleterProps<T = string> {
  /** 字幕，也就是展示在列表中的内容 */ caption?: string;
  /** 展示类型 */ meta?: string;
  /** 名称 */ name?: string;
  /** 插入的值 */ value: T;
  /** 分数，越大的排在越上面 */ score?: number;
  /** 提示所属类型：local|keyword|snippet|function */ type?: string;
  /** 备注 */ remark?: string;
  children?: IEditorCompleterProps<T>[];
  [key: string]: any;
}

export interface IEditorBasicProps {
  /** 编辑器类型 */ editorType?: IEditorType;
  /** 语言模式 */ language?: IEditorLanguage;
  /** 主题风格 */ theme?: IEditorTheme;
  /** 字体大小 */ fontSize?: IEditorFontSize;
  /** 是否只读 */ readOnly?: boolean;
  /** 是否格式化 */ format?: boolean;
}

export interface IEditorCommonProps extends IEditorBasicProps {
  value?: string;
  onChange?: (value: string, event?: any) => void;
  /** 加载完编辑器后回调函数 */ onLoad?: (editor: any) => void;
  /** 暴露方法给父组件 */ handleRef?: any;
  /** 自定义提示 */ completers?: IEditorCompleterProps[];
  /** 确认事件回调函数 */ saveChange?: () => void;
}

export interface IEditorProps extends IEditorCommonProps {}

export interface IEditorAceProps
  extends Omit<
      IAceEditorProps,
      | 'mode'
      | 'theme'
      | 'readOnly'
      | 'fontSize'
      | 'value'
      | 'onChange'
      | 'onLoad'
    >,
    IEditorCommonProps {}

export interface IEditorMonacoProps
  extends Omit<
      MonacoEditorProps,
      'language' | 'theme' | 'readOnly' | 'fontSize' | 'value' | 'onChange'
    >,
    IEditorCommonProps {}

export const EditorDefaultConfig: IEditorBasicProps = {
  editorType: 'monaco',
  language: 'sql',
  theme: 'light',
  fontSize: 14,
  readOnly: false,
  format: false,
};

export interface IOperateGroupItem {
  label: React.ReactNode;
  text?: React.ReactNode;
  value?: any;
  style?: React.CSSProperties;
  type?: IEditorOperateType | ICalculateType;
}

/** 暴露给父组件方法 */
export interface IEditorRefHandles {
  getValue: () => void;
  setValue: (value: string) => void;
  undo: () => void;
  redo: () => void;
  insert: (value: string) => void;
  run: () => void;
  editorEvent: (event: IEditorOperateEvent) => void;
  format: () => void;
}
